I just watched
a CCC
talk
in which the speaker claims Perl is horribly broken. Watching it was
fairly annoying however, since I had to restrain myself from throwing
things at the screen.
If you're going to complain about the language, better make sure you
actually
understand the language first. I won't deny that there are a
few weird constructions in there, but hey. The talk boils down to a
claim that perl is horrible, because the list "data type" is "broken".
First of all, Netanel, in Perl, lists are not arrays. Yes, that's
confusing if you haven't done more than a few hours of Perl, but hear me
out. In Perl, a list is an enumeration of values. A variable with an '@'
sigil is an array; a construct consisting of an opening bracket ('(')
followed by a number of comma- or arrow-separated values (',' or '=>'),
followed by a closing bracket, is a list. Whenever you assign more than
one value to an array or a hash, you need to use a list to enumerate the
values. Subroutines in perl also use lists as arguments or return
values. Yes, that last bit may have been a mistake.
Perl has a concept of "scalar context" and "list context". A scalar
context is what a sub is in when you assign the return value of your sub
to a scalar; a list context is when you assign the return value of your
sub to an array or a hash, or when you use the list construct (the
thing with brackets and commas) with sub calls (instead of
hardcoded values or variables) as the individual values. This works as
follows:
sub magic
if (wantarray())
print "You're asking for a list!";
return ('a', 'b', 'c');
else
print "You're asking for a scalar!";
return 'a';
print ("list: ", magic(), "\n");
print "scalar: " . magic() . "\n";
The above example will produce the following output:
You're asking for a list!
list: abc
You're asking for a scalar!
scalar: a
What happens here? The first
print
line creates a list (because things
are separated by commas); the second one does not (the '.' is perl's
string concatenation operator; as you can only concatenate scalars, the
result is that you call the magic() sub in scalar context).
Yes, seen as how arrays are not lists, the name of the wantarray()
sub is horribly chosen. Anyway.
It is
documented that lists cannot be nested. Lists can only be
one-dimensional constructs. If you create a list, and add another list
as an element (or something that can be converted to a list, like an
array or a hash), then the result is that you get a flattened list. If
you don't want a flattened list, you need to use a
reference instead.
A reference is a
scalar value that, very much like a pointer in C,
contains a reference to another variable. This other variable can be an
array, a hash, or a scalar. But it cannot be a list, because it must be
a variable -- and lists cannot be variables.
If you need to create multi-dimensional constructs, you need to use
references. Taking a reference is done by prepending a backslash to
whatever it is you're trying to take a reference of; or, in the case of
arrays of hashes, one can create an anonymous array or hash with [] resp
. E.g., if you want to add a non-flattened array to a list, you
instead create a reference to an array, like so:
$arrayref = [ 'this', 'is', 'an', 'anonymous', 'array'];
you can now create a multi-dimensional construct:
@multiarray = ('elem1', $arrayref);
Or you can do that in one go:
@multiarray = ('elem1', [ 'this', 'is', 'an', 'anonymous', 'array']);
Alternatively, you can create a non-anonymous array first:
@onedimarray = ('this', 'is', 'not', 'an', 'anonymous', 'array');
@multiarray = ('elem1', \@onedimarray);
In perl, curly brackets can be used to create
a reference to anonymous
hashes, whereas square brackets can be used to create
a reference to
anonymous arrays. This is all a basic part of the language; if you don't
understand that, you simply don't understand Perl. In other words,
whenever you see someone doing this:
%hash = 'a' => 'b' ;
or
@array = [ '1', '2' ];
you can say that they don't understand the language. For reference, the
assignment to
%hash
will result in an (unusable) hash with a single
key that is a reference to an anonymous hash (which cannot be accessed
anymore) and a value of
undef
; the assignment to
@array
will result
in a two-dimensional array with one element in the first dimension, and
two elements in the second.
The CGI.pm fix which Natanel dismisses in the Q&A part of the talk as a
"warning" which won't help (because it would be too late) is actually
a proper fix, which should warn people in all cases. That is, if you do
this:
%hash = 'name' => $name, 'password' => $cgi->param('password') ;
then CGI.pm's
param()
sub will notice that it's being called in
list
context, and issue a warning -- regardless of whether the user is
passing one or two
password
query-parameters. It uses the wantarray()
sub, and produces a warning if that returns true.
In short, Perl is not the horribly broken construct that Natanel claims
it to be. Yes, there are a few surprises (most of which exist for
historical reasons), and yes, those should be fixed. This is why the
Perl community has redone much of perl for Perl 6. But the fact that
there are a few surprises doesn't mean the whole language is broken.
There are surprises in most languages; that is a fact of life.
Yes, the difference between arrays and hashes on the one hand, and
lists on the other hand, is fairly confusing; it took me a while to
understand this. But once you get the hang of it, it's not all that
difficult. And then these two issues that Natanel found (which I suppose
could be described as bugs in the core modules) aren't all that
surprising anymore.
So, in short:
- Don't stop using Perl. However, do make sure that whenever you use a
language, you understand the language, first, so you don't get bitten
by its historical baggage. This is true for any language, not just
Perl.
- Don't assume that just because you found issues with core modules, the
whole language is suddenly broken.
What I do agree with is that if you want to use a language, you should
understand its features. Unfortunately, this single line in the final
slide of Natanel's talk is just about the only thing in the whole talk
that sortof made sense to me.
Ah well.